package com.yishun.springboot.service;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.imageio.ImageIO;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import com.RequestGongWuShu.vehicle;
import com.alibaba.fastjson.JSONObject;
import com.yinquan.util.GetNumber;
import com.yinquan.util.ImagesAndBase64Util;
import com.yishun.springboot.mapper.GwsVehicleMasterDetailedMapper;
import com.yishun.springboot.mapper.PinyiVehicleDetailedMapper;
import com.yishun.springboot.mapper.PinyiVehicleGetdataMapper;
import com.yishun.springboot.mapper.WeiZhongYunVehicleDetailedMapper;
import com.yishun.springboot.mapper.WeiZhongYunVehicleDetailedToPinyiGetDataMapper;
import com.yishun.springboot.mapper.WeiZhongYunVehicleGetDataMapper;
import com.yishun.springboot.pojo.GwsVehicleMasterDetailed;
import com.yishun.springboot.pojo.PinyiVehicleDetailed;
import com.yishun.springboot.pojo.PinyiVehicleGetdata;

import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 定时上传车辆进出数据 经测试工务署进出车辆数据工务署只接收一个月内的数据，超过则会不允许通过该条记录且返回信息里显示：运行时间错误
 *
 * @author XiaoHuang
 * @date 2021年3月24日上午11:48:53
 */
@Slf4j
@Service
@Component
// @SpringBootTest
// @RunWith(SpringRunner.class)
public class GongWuSuTimedUploadVehicleUploadInOutDataService {

	@Autowired
	WeiZhongYunVehicleGetDataMapper weiZhongYunVehicleGetDataMapper;

	@Autowired
	PinyiVehicleDetailedMapper pinyiVehicleDetailedMapper;

	@Autowired
	GwsVehicleMasterDetailedMapper gwsVehicleMasterDetailedMapper;

	@Autowired
	WeiZhongYunVehicleDetailedMapper weiZhongYunVehicleDetailedMapper;

	@Autowired
	PinyiVehicleGetdataMapper pinyiVehicleGetdataMapper;

	@Autowired
	WeiZhongYunVehicleDetailedToPinyiGetDataMapper weiZhongYunVehicleDetailedToPinyiGetDataMapper;

	String shiwugaoapi_key = "d36ac3de10b24a24974fdb8972501782"; // 十五高
	String shiwugaoengCode = "SZSW-009-2020";// 工程编号
	String shiwugaoprojectCode = "XM20190707";// 项目编号

	String api_version = "1.0";
	String baseUlr = "http://szwb.sz.gov.cn:2018/openapi";// 请求地址

	ImagesAndBase64Util iu = new ImagesAndBase64Util();

	// 以下可填写选项二选一。因为工务署只接收一月内的车辆数据
	// 为空表示不填写该选项
	// 若同时为空，则本次中断
	// 若同时不为空，则本次中断

	// 可二选一填写(多少月内的数据)
	Integer howMouth = null;
	// 可二选一填写(多少日内的数据)
	Integer howDay = 15;

	@Async(value = "asyncExecutor")
	@Scheduled(fixedRate = 1000 * 60 * 120)
	public void formalRequestUploadData() {
		log.info("------------定时上传车辆进出数据至工务署------------开始。");
		// 成员方法变量声明
		/**
		 * 入参项目请求参数 (请求大循环赋参)
		 */
		GwsVehicleMasterDetailed gwsVehicleMasterDetailedList = null;

		/**
		 * 入参道闸参数 （请求小循环赋参）因为一个项目有一个以上道闸设备，一对多关系
		 */
		List<PinyiVehicleDetailed> pinyiVehicleList = null;
		List<PinyiVehicleGetdata> pinyiGetData = null;

		String currApiKey = "初始赋值api_key";
		String currEngCode = "初始赋值Eng_code";
		String currProjectCode = "初始赋值Project_code";
		String currApiVersion = "初始赋值Api_version";

		JSONObject body = new JSONObject();
		JSONObject param = new JSONObject();

		// 实例实际请求方法以及设置请求参数
		vehicle v = new vehicle();
		// 入参项目请求参数
		String uploadPhotoUrl = "";
		String photoUrl = "";
		String carNumber = "";
		String deviceNo = "";
		String deviceDataTime = "";

		JSONObject res = new JSONObject();

		List<GwsVehicleMasterDetailed> detaileds = gwsVehicleMasterDetailedMapper.findAll();

		for (int i = 0; i < detaileds.size(); i++) {
			// 根据工务署项目号查出校验信息
			gwsVehicleMasterDetailedList = gwsVehicleMasterDetailedMapper
					.selectOneByGwsProjectCode(detaileds.get(i).getProject_code());
			// 根据工务署项目号查出本地车辆道闸信息
			pinyiVehicleList = pinyiVehicleDetailedMapper
					.selectOneProjectHowManyByGwsProjectCode(detaileds.get(i).getProject_code());

			// 赋值校验信息到请求参数
			currApiKey = gwsVehicleMasterDetailedList.getApi_key();
			currEngCode = gwsVehicleMasterDetailedList.getEng_code();
			currProjectCode = gwsVehicleMasterDetailedList.getProject_code();
			currApiVersion = gwsVehicleMasterDetailedList.getApi_version();

			// 将项目信息先设置在推送工具类
			v.setApi_key(currApiKey);
			v.setEngCode(currEngCode);
			v.setProjectCode(currProjectCode);
			v.setApi_version(gwsVehicleMasterDetailedList.getApi_version());
			v.setBaseUlr(baseUlr);

			// 将项目信息设置在类参数中，因为上次图片用的是类参数
			shiwugaoapi_key = currApiKey;
			shiwugaoengCode = currEngCode;
			shiwugaoprojectCode = currProjectCode;

			// 根据道闸个数进行循环发送http上报请求
			for (int h = 0; h < pinyiVehicleList.size(); h++) {
				// 根据道闸号查出车辆信息
				// weiZhongYunVehicleDetailed = weiZhongYunVehicleDetailedMapper
				// .selectByDeviceNumber(pinyiVehicleList.get(h).getDeviceNo());

				if (howMouth == null && howDay == null) {
					log.warn("请规范填写获取信息根据天数/月份的选项");
					log.warn("--------------------结束~~~~~~~~~~~~~~~~");
					return;
				}
				if (howMouth != null && howDay != null) {
					log.warn("请规范填写获取信息根据天数/月份的选项");
					log.warn("--------------------结束~~~~~~~~~~~~~~~~");
					return;
				}
				if (howMouth != null && howMouth > 1) {
					log.warn("如若填写月份，请只需要填 howMouth 为 1 ");
					log.warn("--------------------结束~~~~~~~~~~~~~~~~");
					return;
				}
				if (howDay != null && howDay > 31) {
					log.warn("请填写31天内的天数 howDay");
					log.warn("--------------------结束~~~~~~~~~~~~~~~~");
					return;
				}

				// 填写"模块" 确定每条通行记录详细
				// 第三个参数表示上传了的也进行上传，填写任意值即表示，上传了的就不上传。是否已经上传根据表字段的checkUploadGwsNumber为空则是未上传来判断

				if (howMouth != null)
					pinyiGetData = pinyiVehicleGetdataMapper.findByProjectNo(pinyiVehicleList.get(h).getProjectNo(),
							howMouth, null);

				if (howDay != null)
					pinyiGetData = pinyiVehicleGetdataMapper.findByProjectNo(pinyiVehicleList.get(h).getProjectNo(),
							howDay, null);

				// 即将删除
				// howmanyWeiZhongYunDetailed =
				// weiZhongYunVehicleGetDataMapper.selectByDeviceNumberAndData(weiZhongYunVehicleDetailed.getDeviceNumber(),dataUtil.currDate());
				// ↑2021-08-03 开始改动，取消为众云的信息同步，十五高的改为品一的暂时假数据

				if (pinyiGetData == null || pinyiGetData.size() == 0) {
					log.warn("本次没有获得数据！");
					log.warn("--------------------结束~~~~~~~~~~~~~~~~");
				}

				for (int j = 0; j < pinyiGetData.size(); j++) {

					// 首先确定要上传什么范围内的进出数据，根据日期查找还是
					// 对于定时推送来说，对于补充推送来说 那就selectByDate();

					String timestamp = DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss");

					Map<String, Object> imageParam1 = new HashMap<String, Object>();
					List<Map<String, Object>> imagesList = new ArrayList<Map<String, Object>>();

					param.put("api_key", currApiKey);
					param.put("project_code", currProjectCode);
					param.put("eng_code", currEngCode);
					param.put("api_version", currApiVersion);
					param.put("timestamp", timestamp);

					carNumber = pinyiGetData.get(j).getTruckNo();

					deviceDataTime = pinyiGetData.get(j).getRecognizeTime();
					if (pinyiGetData.get(j).getRecognizeTime().length() == 16) {
						deviceDataTime = pinyiGetData.get(j).getRecognizeTime() + ":" + GetNumber.getScopeNumber(1, 59);
					}

					// 换成假数据，后续可以if是十五高的项目就换
					deviceNo = pinyiVehicleList.get(h).getDeviceNo();
					// deviceNo =
					// (weiZhongYunVehicleDetailedToPinyiGetDataMapper.selectByDeviceNumber(deviceNo))
					// .getDeviceNumber();

					body.put("type", 1);// √
					body.put("plate_number", carNumber);// √

					body.put("direction", pinyiGetData.get(i).getInOrOut());// √
					// body.put("device_no", deviceNo); // √
					body.put("gate_no", deviceNo); // √
					body.put("region_no", "2");// √
					body.put("region_type", 1);// √
					// body.put("color", 1);// 车辆颜色：蓝，不是必填
					// body.put("lift_type", 1);// 抬杠方式：自动，不是必填
					body.put("region_name", pinyiVehicleList.get(h).getName());// √
					body.put("lift_time", deviceDataTime);// √

					// 解碼成本地圖片，临时放文件到本地文件夹，然后上传到工务署
					// ----start
					String tempData = (deviceDataTime + ".jpg").replace(":", "").replace(" ", "");
					photoUrl = ("E:\\uploadGWSImg\\" + deviceNo + tempData);

					try {
						photoUrl = iu.DecodeBase64(pinyiGetData.get(j).getPhoto(), photoUrl);
					} catch (Exception e) {
						log.error(photoUrl + "--未找到相应文件");
						continue;
					}
					// 注释掉的
					// ---------end

					try {
						uploadPhotoUrl = formalRequestUploadImage(photoUrl);

						if (uploadPhotoUrl == null) {
							log.error("车牌号：" + carNumber + ".时间：" + deviceDataTime + "上传工务署车辆图片失败");
							continue;
						}
					} catch (Exception e) {
						log.error("图片上传到工务署时，结果为空/出现异常未上传." + "车牌号：" + carNumber + ".时间：" + deviceDataTime);
						log.error("异常：" + e.getMessage());
						continue;
					}

					imageParam1.put("img_type", 1);// √
					imageParam1.put("img_data", uploadPhotoUrl);
					imagesList.add(imageParam1);

					body.put("images", imagesList);
					res = v.uploadData(param, body);

					if (("false").equals(res.getString("result"))) {
						log.info(deviceNo + "实时数据推送失败，失败原因" + res.getString("detail_message"));
						continue;
					}
				}
			}
		}
	}

	public String formalRequestUploadImage(String photoUrl) {

		photoUrl = photoUrl.replace("\\", "\\\\");
		vehicle v = new vehicle();
		v.setApi_key(shiwugaoapi_key);
		v.setEngCode(shiwugaoengCode);
		v.setProjectCode(shiwugaoprojectCode);
		v.setApi_version(api_version);
		v.setBaseUlr(baseUlr);
		return v.uploadImage(photoUrl);
	}

	/**
	 * 获取签名
	 *
	 * @param: [apiKey,
	 *             apiVersion, engCode, projectCode, timestamp, body]
	 * @return: java.lang.String
	 */
	public static String getSignature(String apiKey, String apiVersion, String engCode, String projectCode,
			String timestamp, String body) {
		String str4MD5 = String.format("api_key%sapi_version%sbody%seng_code=%sproject_code=%stimestamp%s", apiKey,
				apiVersion, body.isEmpty() ? "{}" : body, engCode, projectCode, timestamp);
		return getMD5Code(str4MD5);
	}

	public static String getMD5Code(String strObj) {
		String resultString = null;
		try {
			resultString = new String(strObj);
			MessageDigest md = MessageDigest.getInstance("MD5");
			Charset charset = Charset.forName("UTF-8");
			resultString = byteToString(md.digest(strObj.getBytes(charset)));
		} catch (NoSuchAlgorithmException ex) {
			ex.printStackTrace();
		}
		return resultString;
	}

	// 转换字节数组为16进制字串
	private static String byteToString(byte[] bByte) {
		StringBuffer sBuffer = new StringBuffer();
		for (int i = 0; i < bByte.length; i++) {
			sBuffer.append(byteToArrayString(bByte[i]));
		}
		return sBuffer.toString();
	}

	private static String byteToArrayString(byte bByte) {
		int iRet = bByte;
		if (iRet < 0) {
			iRet += 256;
		}
		int iD1 = iRet / 16;
		int iD2 = iRet % 16;
		return strDigits[iD1] + strDigits[iD2];
	}

	// 全局数组
	private final static String[] strDigits = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D",
			"E", "F" };

	public static BufferedImage convertURLToImage(String imageUrl) throws IOException {
		URL url = new URL(imageUrl);
		return ImageIO.read(url);
	}

}
